#ifndef _GRID_FIELD_H
#define _GRID_FIELD_H

#include "stdafx.h"
#include "Utility.h"
#include "SceneObj.h"
#include "ConfigManager.h"
#include "DecoSolidObject.h"


class ParticleSys;
class DecoScene;

enum GridType
{
	GT_Air,
	GT_Surface,
	GT_FLuid,
	GT_Solid,
	GT_Sprayer
//  [4/16/2008 HATEVOL] ADDED start
    ,GT_NULL
//  [4/16/2008 HATEVOL] ADDED end
};


class GridField
{
private:
	BOOL isSolidBoundaryCell(INT xIndex, INT yIndex, INT zIndex);
	void updateFluidSolidRatio(BYTE*** solidElements, INT numX, INT numY, INT numZ);
	void checkSolidGridDivergence(DecoSceneObject& solid);
//  [4/23/2008 HATEVOL] ADDED start
	INT normalizeIndex (INT tmpIndex, INT numElement) const;
//  [4/23/2008 HATEVOL] ADDED end
	void calculateVelocityAtGridCenter();
	void moveGridLeftRight(double offset, ParticleSys* particles, DecoScene* scene);
	void moveGridUpDown(double offset, ParticleSys* particles, DecoScene* scene);
	void moveGridFrontBack(double offset, ParticleSys* particles, DecoScene* scene);
public:	
	Box scnBox;
	INT numXElement;
	INT numYElement;
	INT numZElement;
	INT numXVolume;
	INT numYVolume;
	INT numZVolume;
	DOUBLE stepSize;
	DOUBLE stepSizeVol;
	INT volxelPrec;
	DecoStaticMesh* m_mesh;
	vector<Index3> m_compDomain;
	vector<Index3> m_validU;
	vector<Index3> m_validV;
	vector<Index3> m_validW;
	DOUBLE ***u;
	DOUBLE ***v;
	DOUBLE ***w;
	DOUBLE ***p;
	DOUBLE ***phi;
	DecoSolidObject ****pSolid;
	vector3 ***mVelocity;
	DOUBLE ***mVorticity;
	FLOAT ***uFluidVol;
	FLOAT ***vFluidVol;
	FLOAT ***wFluidVol;
	FLOAT ***cFluidVol;
	BOOL ***inDomain;
	BOOL ***prevInDomain;
//	BOOL ***testInDomain; //useless now
	BOOL ***tmpInDomain;
	GridType ***type;
//  [4/16/2008 HATEVOL] ADDED start
	GridType ***fastType;  //2 additional elements in every dimension than type
//  [4/16/2008 HATEVOL] ADDED end
	vector3 ***pTheta;
	vector3 ***mTheta;
#ifdef _SURFACE_TENSION
	vector3 ***pPj;
	vector3 ***mPj;
#endif

	GridField() : numXElement(0), numYElement(0), numZElement(0), stepSize(0), u(NULL), v(NULL), w(NULL), uFluidVol(NULL), vFluidVol(NULL), wFluidVol(NULL), cFluidVol(NULL), p(NULL), phi(NULL), type(NULL), mVelocity(NULL), mVorticity(NULL), 
		pSolid(NULL),
//  [4/17/2008 HATEVOL] ADDED start
        fastType(NULL),
//  [4/17/2008 HATEVOL] ADDED end
		inDomain(NULL), prevInDomain(NULL), pTheta(NULL), mTheta(NULL), tmpInDomain(NULL), m_mesh(NULL) 
#ifdef _SURFACE_TENSION
		, pPj(NULL), mPj(NULL)
#endif
	{
	}
	~GridField()
	{
		if (m_mesh)
			delete m_mesh;
		m_mesh = NULL;
		DestroyAllArrays();
	}
	void SetSceneBox(const Box& _scnBox)
	{
		scnBox = _scnBox;
	}
	void SetNumElement (UINT numX, UINT numY, UINT numZ, BOOL bFullAlloc = TRUE);
	void DestroyAllArrays();
	GridField(const GridField& rhs) : numXElement(0), numYElement(0), numZElement(0), u(NULL), v(NULL), w(NULL), uFluidVol(NULL), vFluidVol(NULL), wFluidVol(NULL), cFluidVol(NULL), p(NULL), phi(NULL), type(NULL), pSolid(NULL),
//  [4/17/2008 HATEVOL] ADDED start
        fastType(NULL),
//  [4/17/2008 HATEVOL] ADDED end
		inDomain(NULL), prevInDomain(NULL), pTheta(NULL), mTheta(NULL), tmpInDomain(NULL)
#ifdef _SURFACE_TENSION
		, pPj(NULL), mPj(NULL)
#endif
	{
		CopyFrom(rhs);
	}

	GridField& operator=(const GridField& rhs)
	{
		if (this == &rhs) return *this;
		CopyFrom(rhs);
		return *this;
	}

	void CopyFrom(const GridField& rhs);
	void CopyVelocityFrom(const GridField& rhs, UINT numX, UINT numY, UINT numZ);
	Box GetGridBox(UINT xIndex, UINT yIndex, UINT zIndex) const;
	vector3 GetGridCenter(UINT xIndex, UINT yIndex, UINT zIndex) const;
	vector3 GetSubGridCenter(UINT xIndex, UINT yIndex, UINT zIndex) const;
	void ClearTypeFlagTo(GridType newType);
	void SetCellType(UINT xIndex, UINT yIndex, UINT zIndex, GridType newType);
	void Render(DecoRenderInterface* RI, DecoLight** Lights, UINT numEffectiveLights);
	//void Voxelize(DecoSceneObject& solid);
	const vector<Index3>& VoxelizeSolid(DecoSceneObject& solid, BYTE*** solidElements, INT numX, INT numY, INT numZ);
	void VoxelizeSprayer(BYTE*** sprayerElements, INT numX, INT numY, INT numZ);
	//BOOL CompareVoxelization(const GridField& rhs);
	void updateVoxelizeType(BYTE*** voxElements, INT numX, INT numY, INT numZ, GridType type, vector<Index3>* updateDomain = NULL, INT id = 0);
	vector3 fromLocalGridToWorld(const vector3& pos, INT xIndex, INT yIndex, INT zIndex) const;
	vector3 fromWorldToLocalGrid(const vector3& pos, UINT& xIndex, UINT& yIndex, UINT& zIndex) const;
	DOUBLE SamplePhi(const vector3& pos) const;
	DOUBLE SamplePressure(const vector3& pos) const;
	vector3 SampleVelocity(const vector3& pos, GridField* coarseLayer) const;
	vector3 SampleVelocity(const vector3& pos) const;
	DOUBLE SampleU(const vector3& pos, GridField* coarseLayer, BOOL bPrintf = FALSE) const;
	DOUBLE SampleV(const vector3& pos, GridField* coarseLayer) const;
	DOUBLE SampleW(const vector3& pos, GridField* coarseLayer) const;
	DOUBLE SampleU(const vector3& pos, BOOL bPrintf = FALSE) const;
	DOUBLE SampleV(const vector3& pos) const;
	DOUBLE SampleW(const vector3& pos) const;
//  [4/24/2008 HATEVOL] ADDED start
	DOUBLE SampleUWithLocalGrid(const vector3& pos, const vector3& localPos, INT xIndex, INT yIndex, INT zIndex, GridField* coarseLayer, BOOL bPrintf = FALSE) const;
	DOUBLE SampleVWithLocalGrid(const vector3& pos, const vector3& localPos, INT xIndex, INT yIndex, INT zIndex, GridField* coarseLayer) const;
	DOUBLE SampleWWithLocalGrid(const vector3& pos, const vector3& localPos, INT xIndex, INT yIndex, INT zIndex, GridField* coarseLayer) const;
	DOUBLE SampleUWithLocalGrid(const vector3& localPos, INT xIndex, INT yIndex, INT zIndex, BOOL bPrintf = FALSE) const;
	DOUBLE SampleVWithLocalGrid(const vector3& localPos, INT xIndex, INT yIndex, INT zIndex) const;
	DOUBLE SampleWWithLocalGrid(const vector3& localPos, INT xIndex, INT yIndex, INT zIndex) const;

	void DumpSolid();
//  [4/24/2008 HATEVOL] ADDED end
	DOUBLE SampleScalerValue(const vector3& pos, DOUBLE*** scaler) const;
	void updateSolidVelocity(DecoSceneObject& solid);
	const vector<Index3>& updateSolidType(DecoSceneObject& solid, BYTE*** solidElements, INT numX, INT numY, INT numZ, INT id);

	void CalculateVorticity();
	double GetMaxVorticiyMagnitute() const;
	double GetMaxPressureMagnitute() const;
	double GetMinPressureMagnitute() const;
	bool MoveGrid(const vector3& offset, ParticleSys* particles, DecoScene* scene);
#ifdef _SLC
	BOOL IsThinSheetCell(INT xIndex, INT yIndex, INT zIndex);
	BOOL IsInvalidAirCell(INT i, INT j, INT k);
#endif
#ifdef _ACC_BOUNDARY
	BOOL checkSolidValid(INT i, INT j, INT k);
#endif
	BOOL isFluidCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isAirCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isSolidCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isBoundaryCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isSurfaceCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isSprayerCell(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isInDomain(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isNearSolid(INT xIndex, INT yIndex, INT zIndex) const;
	BOOL isVelocityValid(char dim, INT i, INT j, INT k) const;
	friend DecoArchive& operator<< (DecoArchive& Ar, const GridField& field);
	friend DecoArchive& operator>> (DecoArchive& Ar, GridField& field);
};


#endif
